from dataclasses import dataclass, field
from os import PathLike, environ
from pathlib import Path
from typing import List, Literal, Optional
from benedict import benedict
import logging
import re


def expand_env_variables(conf_dict: dict, envs=None):
    """Expand envitonment variables inplace.

    Replace values like `$VAR_NAME` with `VAR_NAME` env variable values.
    Note that only UPPERCASE variable names are supported.

    Args:
        conf_dict: Ditionary in which replace vars.
        envs: Environmental variables. If None, uses `os.environ`.

    """
    if envs is None:
        envs = environ

    var_re = re.compile(r'^\$([A-Z0-9_]*)$')
    result = dict()
    for k, v in conf_dict.items():
        if isinstance(v, dict):
            updated_value = expand_env_variables(v, envs)
        elif isinstance(v, str):
            match = var_re.match(v)
            if match is None:
                updated_value = v
            else:
                env_var = match.group(1)
                if env_var not in envs:
                    raise ValueError(
                        f'Env variable {env_var!r} is not defined. ' +
                        'Set it or update `config.yaml` file.'
                    )
                updated_value = envs[env_var]
        else:
            updated_value = v
        result[k] = updated_value
    return result


class LoadableConfig:
    @classmethod
    def load(cls, path: PathLike):
        if Path(path).exists():
            conf_dict = benedict(path)
            conf_dict = expand_env_variables(conf_dict)
            return cls(**conf_dict)
        else:
            logging.warning(f'The config file {path!r} does not exist')
            return cls()



@dataclass
class PaperAIConfig(LoadableConfig):
    gigachat_token: str
    gigachat_scope: Literal['GIGACHAT_API_CORP', 'GIGACHAT_API_PERS']
    semanticscholar_api_key: str
